<script setup>
import {Notification} from "@arco-design/web-vue";
import {onMounted, ref} from 'vue'
import {SocketD} from '@noear/socket.d'
import {Terminal} from '@xterm/xterm';
import '@xterm/xterm/css/xterm.css'
import Bus from "@/utils/bus.js";
import Cookies from "js-cookie";

const emits = defineEmits(["delayEvent"])
const props = defineProps(['id'])
const terminalRef = ref(null)
const terminal = ref(null)
const session = ref(null);
let heartbeat = null;
console.log(props.id)
onMounted(async () => {
  Bus.emit('loading', {type: true, tip: '连接终端中...'})
  const stt = setTimeout(() => {
    Bus.emit('loading', false)
    Notification.warning('连接超时')
  }, 10000)
  const port = window.location.port === '' ? '80' : window.location.port;
  session.value = await SocketD.createClient("sd:ws://" + window.location.hostname + ":" + port + "/api/ws?token=" + Cookies.get('SOLONID'))
      .listen(SocketD.newEventListener()
          .doOnOpen(s => {
            if (!terminal.value) {
              initTerminal()
              setTimeout(() => {
                // 发起初始化
                var size = getSize(terminal)
                sendSession(s, 'init', JSON.stringify({
                  columns: size.columns,
                  rows: size.rows
                }));
                // 首次延迟测试
                sendSession(session.value, 'ping', new Date().getTime())
              }, 500)
            }
          })
          .doOnMessage((s, m) => {
            const type = m.entity().meta('type');
            if (type === 'print') {
              terminal.value.write(m.entity().dataAsString());
            } else if (type === 'initComplete') {
              setTimeout(() => {
                Bus.emit('loading', false)
                Notification.success('终端初始化完成')
                clearTimeout(stt)
              }, 500)
              if (!heartbeat) {
                heartbeat = setInterval(() => {
                  testPing()
                }, 8000)
              }
            } else if (type === 'pong') {
              const time = m.entity().dataAsString();
              const delay = new Date().getTime() - parseInt(time, 10)
              emits('delayEvent', props.id, delay)
            } else if (type === 'close') {
              console.log('关闭终端')
            }
          })
          .doOnClose(s => {
            terminal.value.writeln('')
            terminal.value.writeln('已经失去服务端连接...')
            terminal.value.writeln('重连中...')
            emits('delayEvent', props.id, -1)
          })
      )
      .open()
})

const testPing = () => {
  if (session.value && session.value.isValid()) {
    sendSession(session.value, 'ping', new Date().getTime())
  } else {
    emits('delayEvent', props.id, -1)
  }
}

// 及时调整宽度
const getSize = () => {
  const columns = parseInt(window.innerWidth / 10, 10) - 1
  var rows = 10;
  var innerHeight = window.innerHeight - 145
  rows = parseInt(innerHeight / 15, 10) - 7
  return {columns, rows}
}

/**
 * 发送指令
 * @param session 会话
 * @param action 动作
 * @param str 内容，必须是string
 */
const sendSession = (session, action, str) => {
  const entity = SocketD.newEntity(str);
  entity.metaPut('type', action)
  if (session.isValid())
    session.send("/", entity);
}
/**
 * 发送指令
 * @param action 动作
 * @param str 内容，必须是string
 */
const send = (action, str) => {
  const entity = SocketD.newEntity(str);
  entity.metaPut('type', action)
  if (session.value.isValid())
    session.value.send("/", entity);
}

// 初始化Terminal
const initTerminal = () => {
  var size = getSize();
  terminal.value = new Terminal({
    // lineHeight: 1.2,
    fontSize: 14,
    columns: size.columns,
    rows: size.rows,
    // 光标闪烁
    cursorBlink: true,
  })
  terminal.value.open(terminalRef.value) //挂载dom窗口
  // terminal.value.open(document.getElementById('tr')) //挂载dom窗口
  terminal.value.onData((command) => {
    send('cmd', command);
  })
}
const resizeTerm = (terminal) => {
  const {columns, rows} = getSize(terminal)
  if (columns !== terminal.options.cols || rows !== terminal.options.rows) {
    terminal.resize(columns, rows);
    if (wsSession)
      send('resize', JSON.stringify({
        columns,
        rows,
      }));
  }
};

const closeAll = () => {
  Bus.emit('loading', {type: true, tip: '关闭终端...'})
  sendSession(session.value, 'close', '')
  setTimeout(() => {
    Bus.emit('loading', false)
    // 关闭session
    session.value.close()
    Bus.emit('shell', {type: 'delete_terminal', key: props.id})
  }, 1000)
  terminal.value.writeln('')
  terminal.value.writeln('服务端已经关闭')
}

Bus.on('shell', data => {
  if (data.type === 'delete' && props.id === data.key) {
    clearInterval(heartbeat)
    closeAll()
  }
})
</script>

<template>
  <div class="flex-column">
    <div ref="terminalRef"></div>
  </div>
</template>

<style scoped>

</style>